package com.hxlc.util;

import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.*;

/**
 * 反射提取值
 */
public class RectField {


    /**
     * 反射提取集合的值
     *
     * @param <T>
     * @return
     */
    public static <T> List<T> getBeanFields(Collection collection, String fieldName) {
        if (!CollectionUtils.isNotBlank(collection)) {
            return null;
        }
        List<T> tList = new ArrayList<T>();
        for (Object o : collection) {
            T beanField = getBeanField(o, fieldName);
            if (beanField != null) tList.add(beanField);
        }
        return tList;
    }


    /**
     * 提取数据 进行索引
     *
     * @param collection
     * @param fieldName
     * @param <M>
     * @param <T>
     * @return
     */
    public static <M, T> Map<M, T> conversionIndex(Collection<T> collection, String fieldName) {
        Map<M, T> indexMap = new HashMap<M, T>();
        for (T t : collection) {
            M index = getBeanField(t, fieldName);
            if (index != null) indexMap.put(index, t);
        }
        return indexMap;
    }


    /**
     * 提取数据 进行索引
     *
     * @param collection
     * @param <M>
     * @param <T>
     * @return
     */
    public static <M, T> Map<M, List<T>> conversionIndexToList(Collection<T> collection, String... fieldNames) {
        Map<M, List<T>> indexMap = new LinkedHashMap<>();
        if (fieldNames == null) {
            return indexMap;
        }
        for (T t : collection) {
            M index = getBeanFields(t, fieldNames);
            if(index != null) {
                List<T> ts = indexMap.get(index);
                if (ts == null) {
                    ts = new ArrayList<T>();
                    indexMap.put(index, ts);
                }
                ts.add(t);
            }
        }
        return indexMap;
    }

    /**
     * 提取数据 进行索引
     *
     * @param collection
     * @param <M>
     * @param <T>
     * @return
     */
    public static <M, T> Map<M, List<T>> conversionIndexToList(Collection<T> collection, String fieldNames) {
        Map<M, List<T>> indexMap = new HashMap<M, List<T>>();
        if (fieldNames == null) {
            return indexMap;
        }
        for (T t : collection) {
            M index = getBeanField(t, fieldNames);
            if (index != null) {
                List<T> ts = indexMap.get(index);
                if (ts == null) {
                    ts = new ArrayList<T>();
                    indexMap.put(index, ts);
                }
                ts.add(t);
            }
        }
        return indexMap;
    }

    /**
     * 提取数据 进行索引
     *
     * @param collection
     * @param <M>
     * @param <T>
     * @return
     */
    public static <M, T> LinkedHashMap<M, List<T>> conversionLinkedIndexToList(Collection<T> collection, String fieldNames) {
        LinkedHashMap<M, List<T>> indexMap = new LinkedHashMap<>();
        if (fieldNames == null) {
            return indexMap;
        }
        for (T t : collection) {
            M index = getBeanField(t, fieldNames);
            if(index != null) {
                List<T> ts = indexMap.get(index);
                if (ts == null) {
                    ts = new ArrayList<T>();
                    indexMap.put(index, ts);
                }
                ts.add(t);
            }
        }
        return indexMap;
    }


    /**
     * 使用多个字段作为索引
     *
     * @param collection
     * @param fieldNames
     * @param <M>
     * @param <T>
     * @return
     */
    public static <M, T> Map<M, T> conversionIndex(Collection<T> collection, String... fieldNames) {
        Map<M, T> indexMap = new HashMap<M, T>();
        if (!CollectionUtils.isNotBlank(collection)) {
            return indexMap;
        }
        for (T t : collection) {
            M index = getBeanFields(t, fieldNames);
            if (index != null) indexMap.put(index, t);
        }
        return indexMap;
    }

    /**
     * 根据字段取值
     *
     * @param o
     * @param fieldNames
     * @param <T>
     * @return
     */
    public static <T> T getBeanFields(Object o, String... fieldNames) {
        if (o instanceof Map) {
            String[] ret = new String[fieldNames.length];
            for (int i = 0; i < fieldNames.length; i++) {
                Object v = ((Map) o).get(fieldNames[i]);
                if (v == null) {
                    continue;
                }
                ret[i] = v.toString();
//                ret = ret+"="+ declaredField.get(o).toString();
            }
            String rets = HxStringUtils.join(ret, "=");
            return (T) rets;
        }
        Class<?> aClass = o.getClass();
        try {
            String[] ret = new String[fieldNames.length];
            for (int i = 0; i < fieldNames.length; i++) {
                Field declaredField = getFieldSupper(fieldNames[i], aClass);
                if (declaredField == null) {
                    continue;
                }
                declaredField.setAccessible(true);
                if (declaredField.get(o) == null) {
                    return null;
                }
                ret[i] = declaredField.get(o).toString();
//                ret = ret+"="+ declaredField.get(o).toString();
            }
            String rets = HxStringUtils.join(ret, "=");
            return (T) rets;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 根据字段取值
     *
     * @param o
     * @param fieldName
     * @param <T>
     * @return
     */
    public static <T> T getBeanField(Object o, String fieldName) {
        if (o instanceof Map) {
            return (T) ((Map) o).get(fieldName);
        }
        Class<?> aClass = o.getClass();
        try {
            Field declaredField = getFieldSupper(fieldName, aClass);
            if (declaredField == null) {
                return null;
            }
            declaredField.setAccessible(true);
            return (T) declaredField.get(o);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 移除集合中 不符合规则的数据
     *
     * @param m
     * @param fieldName
     * @param flag
     * @param <M>
     * @param <T>
     * @return
     */
    public static <M extends Collection<T>, T> M removeIsNullField(M m, String fieldName, String flag) {
        if (!CollectionUtils.isNotBlank(m)) {
            return m;
        }
        for (Iterator<T> iterator = m.iterator(); iterator.hasNext(); ) {
            T next = iterator.next();
            if (isFieldFlag(next, fieldName, flag)) {
                iterator.remove();
            }
        }
        return m;
    }

    /**
     * 看值是否和标识符一样
     *
     * @return
     */
    public static <T> boolean isFieldFlag(T t, String fieldName, String flag) {
        Class aClass = t.getClass();
        try {
            Field declaredField = getFieldSupper(fieldName, aClass);
            if (declaredField == null) {
                return false;
            }
            declaredField.setAccessible(true);
            Object o = declaredField.get(t);
            return Objects.equals(flag, o);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 获取包括父类在内的指定字段
     *
     * @param fieldName
     * @param clazz
     * @return
     */
    public static Field getFieldSupper(String fieldName, Class clazz) {
        Field declaredField = null;
        try {
            declaredField = clazz.getDeclaredField(fieldName);
        } catch (NoSuchFieldException e) {
            clazz = clazz.getSuperclass();
            if (clazz == null) {
                return null;
            }
            declaredField = getFieldSupper(fieldName, clazz);
        }
        return declaredField;
    }


    /**
     * 获取包括父类在内
     *
     * @param clazz
     * @return
     */
    public static List<Field> getFieldSuppers(Class clazz) {
        List<Field> fieldList = new ArrayList<Field>();
        while (clazz != null) {
            fieldList.addAll(Arrays.asList(clazz.getDeclaredFields()));
            clazz = clazz.getSuperclass();
        }
        return fieldList;
    }

    /**
     * 提取value值
     *
     * @param <K>
     * @param <T>
     * @return
     */
    public static <K, T> List<T> extractValues(Map<K, T> ktMap, Comparator<T> tComparable) {
        List<T> values = new ArrayList<T>();
        ktMap.forEach((k, t) -> values.add(t));
        if (tComparable != null) values.sort(tComparable);
        return values;
    }

    public static <T> void setFieldValue(T obj, String field, Object value) {
        Class<?> aClass = obj.getClass();
        try {
            Field declaredField = aClass.getDeclaredField(field);
            Class<?> type = declaredField.getType();
            if (type == Integer.class) {
                value = new BigDecimal(value.toString()).intValue();
            } else if (type == Double.class) {
                value = new BigDecimal(value.toString()).doubleValue();
            } else if (type == Long.class) {
                value = new BigDecimal(value.toString()).longValue();
            } else if (type == Short.class) {
                value = new BigDecimal(value.toString()).shortValue();
            } else if (type == Byte.class) {
                value = new BigDecimal(value.toString()).byteValue();
            } else if (type == Float.class) {
                value = new BigDecimal(value.toString()).floatValue();
            } else if (type == BigDecimal.class) {
                value = new BigDecimal(value.toString());
            }
            declaredField.setAccessible(true);
            declaredField.set(obj, value);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    public static <T> void setFieldValue(Class clazz, T obj, String field, Object value) {
        Class<?> aClass = obj.getClass();
        try {
            Field declaredField = RectField.getFieldSupper(field, clazz);
            Class<?> type = declaredField.getType();
            if (type.getTypeName().equals("int")) {
                value = new BigDecimal(value.toString()).intValue();
            } else if (type.getTypeName().equals("double")) {
                value = new BigDecimal(value.toString()).doubleValue();
            } else if (type.getTypeName().equals("long")) {
                value = new BigDecimal(value.toString()).longValue();
            } else if (type.getTypeName().equals("short")) {
                value = new BigDecimal(value.toString()).shortValue();
            } else if (type.getTypeName().equals("byte")) {
                value = new BigDecimal(value.toString()).byteValue();
            } else if (type.getTypeName().equals("float")) {
                value = new BigDecimal(value.toString()).floatValue();
            } else if (type.getTypeName().equals("String")) {
                value = new BigDecimal(value.toString());
            } else {
                Type genericType = declaredField.getGenericType();
                if (genericType.getTypeName().equals("T")) {
                }
            }
            declaredField.setAccessible(true);
            declaredField.set(obj, value);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}
